﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Portal.WebControls;

namespace SPRA.Helpers
{
    internal class ListItemHelper
    {
        private static readonly Guid AttachmentsFieldId = new Guid("67df98f4-9dec-48ff-a553-29bece9c5bf4");

        private readonly SPListItem sourceItem;
        private readonly SPList sourceList;

        public ListItemHelper(SPListItem listItem)
        {
            if (listItem == null) throw new ArgumentNullException("listItem");

            this.sourceItem = listItem;
            this.sourceList = sourceItem.ParentList;
        }

        public SPListItem SourceItem
        {
            get { return sourceItem; }
        }

        public SPList SourceList
        {
            get { return sourceList; }
        }

        public SPListItem Copy()
        {
            return Copy(null);
        }

        public SPListItem Copy(List<Guid> fields)
        {
            sourceItem.Web.AllowUnsafeUpdates = true;
            SPListItem result = CopyGeneralItem(fields);
            sourceItem.Web.AllowUnsafeUpdates = false;

            return result;
        }

        public SPListItem Copy(List<Guid> fields, SPFolder folder)
        {
            sourceItem.Web.AllowUnsafeUpdates = true;
            SPListItem result = CopyGeneralItem(fields, folder);
            sourceItem.Web.AllowUnsafeUpdates = false;

            return result;
        }

        public SPListItem CopyGeneralItem(IEnumerable<Guid> fields)
        {
            var newItem = sourceList.Items.Add();
            CopyFields(sourceItem, newItem, fields);
            //CommonHelper.SyncRoleAssignments(sourceItem, newItem);
            return newItem;
        }
        public SPListItem CopyGeneralItem(IEnumerable<Guid> fields, SPFolder folder)
        {
            var newItem =
                folder == null ?
                sourceList.Items.Add() :
                sourceList.Items.Add(folder.ServerRelativeUrl, SPFileSystemObjectType.File);

            CopyFields(sourceItem, newItem, fields);
            //CommonHelper.SyncRoleAssignments(sourceItem, newItem);
            return newItem;
        }

        internal void ReAssignPermissionsAfterCopy(SPListItem item, SPUser user)
        {
            SPSecurity.RunWithElevatedPrivileges(() =>
                {
                    using(SPSite eSite = new SPSite(item.ParentList.ParentWeb.Site.ID))
                    using (SPWeb eWeb = eSite.OpenWeb(item.Web.ID))
                    {
                        eWeb.AllowUnsafeUpdates = true;
                        SPList eList = eWeb.Lists[item.ParentList.ID];
                        SPListItem newItem = eList.GetItemById(item.ID);
                        WipeRoleAssignments(item);
                        SPRoleAssignment ra = new SPRoleAssignment(user);
                        ra.RoleDefinitionBindings.Add(item.Web.RoleDefinitions.GetByType(SPRoleType.Contributor));
                        newItem.RoleAssignments.Add(ra);
                        eWeb.AllowUnsafeUpdates = false;
                    }
                });
        }

        public void WipeRoleAssignments(SPListItem item)
        {
            if (item.HasUniqueRoleAssignments)
                while (item.RoleAssignments.Count > 0)
                    item.RoleAssignments.RemoveById(0);
            else
                item.BreakRoleInheritance(false);
        }

        private static void CopyFields(SPListItem sourceItem, SPListItem newItem, IEnumerable<Guid> requestedFields)
        {
            var contentTypeFields = sourceItem.ContentType.Fields.Cast<SPField>()
                .Where(f => !(f.ReadOnlyField || f.Hidden)).Select(f => f.Id);

            var allFields = sourceItem.Fields.Cast<SPField>()
                .Where(f => !(f.ReadOnlyField || f.Hidden)).Select(f => f.Id);

            var fieldsToCopy = allFields;

            if (requestedFields != null)
                fieldsToCopy = requestedFields;

            newItem[SPBuiltInFieldId.ContentTypeId] = sourceItem.ContentType.Id;
            newItem[SPBuiltInFieldId.ContentType] = sourceItem.ContentType;
            foreach (var f in fieldsToCopy)
            {
                // handle attachments later
                if (f == AttachmentsFieldId) continue;

                // copy common fields
                Guid f1 = f;
                var foundField = newItem.Fields.Cast<SPField>().FirstOrDefault(x => x.Id == f1);
                if (foundField != null)
                {
                    newItem[f] = sourceItem[f];
                }
                // copy additional fields for bdc
                BusinessDataField bdcField = sourceItem.Fields[f] as BusinessDataField;
                if (bdcField != null)
                {
                    newItem[bdcField.RelatedField] = sourceItem[bdcField.RelatedField];
                }
            }

            newItem.Update();

            // handle attachments
            if (requestedFields != null && requestedFields.Contains(AttachmentsFieldId))
            {
                foreach (string fileName in sourceItem.Attachments)
                {
                    SPFile file = sourceItem.ParentList.ParentWeb.GetFile(sourceItem.Attachments.UrlPrefix + fileName);
                    byte[] imageData = file.OpenBinary();
                    newItem.Attachments.AddNow(fileName, imageData);
                }
                newItem.SystemUpdate(false);
            }
        }

        public static void CopyFields(SPListItem sourceItem, SPListItem newItem)
        {
            CopyFields(sourceItem, newItem, null);
        }
    }
}
